﻿namespace ImageProcessing
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Text;


    /// <summary>
    /// calcOperation for operation on image like add,sub,or and sum ...
    /// </summary>
    public class CalcOperation
    {
        /// <summary>
        /// And the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>new image added imge1 and image2</returns>
        public static ImageStructure[,] AndIamges(ImageStructure[,] image1, ImageStructure[,] image2)
        {

            int height = image1.GetLength(0);
            int width = image1.GetLength(1);

            int height2 = image2.GetLength(0);
            int width2 = image2.GetLength(1);

            if (height != height2 && width != width2)
            {
                //ResizeImage.BiLineResize(width, height, image2);
                //ResizeImage.BiLineResize(width, height, image2);
            }

            ImageStructure[,] newImage = new ImageStructure[height, width];
            Bitmap b1, b2, br;
            b1 = OpenImage.ConvertStructureToBitmap(image1, width, height);
            b2 = OpenImage.ConvertStructureToBitmap(image2, width, height);
            br = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            unsafe
            {
                BitmapData bmd1, bmd2, bmd3;
                bmd1 = b1.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd2 = b2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd3 = br.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int exrtraBytes = bmd1.Stride - width * 3;
                PHFastCpp.PHAnd((int)bmd1.Scan0, (int)bmd2.Scan0, (int)bmd3.Scan0, width, height, exrtraBytes);

                br.UnlockBits(bmd3);
                b1.UnlockBits(bmd1);
                b2.UnlockBits(bmd2);

                return Operations.ConvertBitmapToStructure(br);
            }

        }

        /// <summary>
        /// Subs the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>new image subtract imge1 and image2</returns>
        public static ImageStructure[,] SubIamgesOld(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            int height = image1.GetLength(0);
            int width = image1.GetLength(1);
            ImageStructure[,] newImage = new ImageStructure[height, width];
            double tempR = 0;
            double tempG = 0;
            double tempB = 0;

            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    tempR = Math.Abs(image1[i, j].R - image2[i, j].R);
                    tempG = Math.Abs(image1[i, j].G - image2[i, j].G);
                    tempB = Math.Abs(image1[i, j].B - image2[i, j].B);

                    tempR = tempR > 255 ? 255 : tempR;
                    tempR = tempR < 0 ? 0 : tempR;

                    tempG = tempG > 255 ? 255 : tempG;
                    tempG = tempG < 0 ? 0 : tempG;

                    tempB = tempB > 255 ? 255 : tempB;
                    tempB = tempB < 0 ? 0 : tempB;

                    newImage[i, j].R = (byte)tempR;
                    newImage[i, j].G = (byte)tempG;
                    newImage[i, j].B = (byte)tempB;
                }
            }

            return newImage;
        }

        /// <summary>
        /// Subs the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>new image subtract imge1 and image2</returns>
        public static ImageStructure[,] SubIamges(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            int height = image1.GetLength(0);
            int width = image1.GetLength(1);

            int height2 = image2.GetLength(0);
            int width2 = image2.GetLength(1);

            if (height != height2 && width != width2)
            {
                //ResizeImage.BiLineResize(width, height, image2);
            }

            ImageStructure[,] newImage = new ImageStructure[height, width];
            Bitmap b1, b2, br;
            b1 = OpenImage.ConvertStructureToBitmap(image1, width, height);
            b2 = OpenImage.ConvertStructureToBitmap(image2, width, height);
            br = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            unsafe
            {
                BitmapData bmd1, bmd2, bmd3;
                bmd1 = b1.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd2 = b2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd3 = br.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int exrtraBytes = bmd1.Stride - width * 3;
                PHFastCpp.PHSub((int)bmd1.Scan0, (int)bmd2.Scan0, (int)bmd3.Scan0, width, height, exrtraBytes);

                br.UnlockBits(bmd3);
                b1.UnlockBits(bmd1);
                b2.UnlockBits(bmd2);

                return Operations.ConvertBitmapToStructure(br);
            }
        }

        /// <summary>
        /// Ors the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>new image Or imge1 , image2</returns>
        public static ImageStructure[,] OrIamges(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            int height = image1.GetLength(0);
            int width = image1.GetLength(1);

            int height2 = image2.GetLength(0);
            int width2 = image2.GetLength(1);

            if (height != height2 && width != width2)
            {
                //ResizeImage.BiLineResize(width, height, image2);
            }

            ImageStructure[,] newImage = new ImageStructure[height, width];
            Bitmap b1, b2, br;
            b1 = OpenImage.ConvertStructureToBitmap(image1, width, height);
            b2 = OpenImage.ConvertStructureToBitmap(image2, width, height);
            br = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            unsafe
            {
                BitmapData bmd1, bmd2, bmd3;
                bmd1 = b1.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd2 = b2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd3 = br.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int exrtraBytes = bmd1.Stride - width * 3;
                PHFastCpp.PHOr((int)bmd1.Scan0, (int)bmd2.Scan0, (int)bmd3.Scan0, width, height, exrtraBytes);

                br.UnlockBits(bmd3);
                b1.UnlockBits(bmd1);
                b2.UnlockBits(bmd2);

                return Operations.ConvertBitmapToStructure(br);
            }
        }

        /// <summary>
        /// Prudects the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>new image prudect imge1 and image2</returns>
        public static ImageStructure[,] PrudectIamges(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            int height = image1.GetLength(0);
            int width = image1.GetLength(1);
            ImageStructure[,] newImage = new ImageStructure[height, width];
            double[,] tempR = new double[height, width];
            double[,] tempG = new double[height, width];
            double[,] tempB = new double[height, width];

            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    tempR[i, j] = image1[i, j].R * image2[i, j].R;
                    tempG[i, j] = image1[i, j].G * image2[i, j].G;
                    tempB[i, j] = image1[i, j].B * image2[i, j].B;
                }
            }

            newImage = PixelOperation.Normalization(newImage, height, width, tempR, tempG, tempR);
            return newImage;
        }

        /// <summary>
        /// Sums the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <param name="fraction">The fraction.</param>
        /// <returns>
        /// new image sum imge1 and image2
        /// </returns>
        public static ImageStructure[,] SumIamges(ImageStructure[,] image1, ImageStructure[,] image2, double fraction)
        {
            int height = image1.GetLength(0);
            int width = image1.GetLength(1);

            int height2 = image2.GetLength(0);
            int width2 = image2.GetLength(1);

            if (height != height2 && width != width2)
            {
                //ResizeImage.BiLineResize(width, height, image2);
            }

            ImageStructure[,] newImage = new ImageStructure[height, width];
            Bitmap b1, b2, br;
            b1 = OpenImage.ConvertStructureToBitmap(image1, width, height);
            b2 = OpenImage.ConvertStructureToBitmap(image2, width, height);
            br = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            unsafe
            {
                BitmapData bmd1, bmd2, bmd3;
                bmd1 = b1.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd2 = b2.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bmd3 = br.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int exrtraBytes = bmd1.Stride - width * 3;
                PHFastCpp.PHAdd((int)bmd1.Scan0, (int)bmd2.Scan0, (int)bmd3.Scan0, width, height, exrtraBytes, (float)fraction);

                br.UnlockBits(bmd3);
                b1.UnlockBits(bmd1);
                b2.UnlockBits(bmd2);

                return Operations.ConvertBitmapToStructure(br);
            }
        }

        /// <summary>
        /// Xors the images.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>image1 Xor iamge2</returns>
        public static ImageStructure[,] XorImages(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            // p xor q=(p and not q)or(notp ans q)
            ImageStructure[,] notP = PixelOperation.NotOperation(image1);
            ImageStructure[,] notQ = PixelOperation.NotOperation(image2);
            ImageStructure[,] pandNotq = CalcOperation.AndIamges(image1, notQ);
            ImageStructure[,] notPAndQ = CalcOperation.AndIamges(notP, image2);
            ImageStructure[,] newImage = CalcOperation.OrIamges(pandNotq, notPAndQ);
            return newImage;
        }

        /// <summary>
        /// Nands the imges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>image1 nand image2</returns>
        public static ImageStructure[,] NAndImges(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            ImageStructure[,] and = CalcOperation.AndIamges(image1, image2);
            ImageStructure[,] newImage = PixelOperation.NotOperation(and);
            return newImage;
        }

        /// <summary>
        /// Ns the or imges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>image1 xor image2</returns>
        public static ImageStructure[,] NOrImges(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            ImageStructure[,] or = CalcOperation.OrIamges(image1, image2);
            ImageStructure[,] newImage = PixelOperation.NotOperation(or);
            return newImage;
        }

        /// <summary>
        /// Xs the nor images.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>image one xnor image2</returns>
        public static ImageStructure[,] XNorImages(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            ImageStructure[,] newImage = PixelOperation.NotOperation(CalcOperation.XorImages(image1, image2));
            return newImage;
        }

        /// <summary>
        /// Implieses the images.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>p implies q</returns>
        public static ImageStructure[,] ImpliesImages(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            // p ---> q=notP or Q
            ImageStructure[,] newImage = CalcOperation.OrIamges(PixelOperation.NotOperation(image1), image2);
            return newImage;
        }

        /// <summary>
        /// Iffs the and onle if images.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="image2">The image2.</param>
        /// <returns>image1 iff image2</returns>
        public static ImageStructure[,] Image1IffImage2(ImageStructure[,] image1, ImageStructure[,] image2)
        {
            // p <---> q=P-->Q and Q---P
            ImageStructure[,] imppThenQ = CalcOperation.ImpliesImages(image1, image2);
            ImageStructure[,] impqThenP = CalcOperation.ImpliesImages(image2, image1);
            ImageStructure[,] newImage = CalcOperation.AndIamges(imppThenQ, impqThenP);
            return newImage;
        }

        /// <summary>
        /// Sums the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="color">The color.</param>
        /// <param name="fraction">The fraction.</param>
        /// <returns>
        /// new image sum imge1 and image2
        /// </returns>
        public static ImageStructure[,] AddColor2image(ImageStructure[,] image1, Color color, PostProcessing pp)
        {
            int heigth = image1.GetLength(0);
            int width = image1.GetLength(1);
            ImageStructure[,] newImage = new ImageStructure[heigth, width];
            double[,] red = new double[heigth, width];
            double[,] green = new double[heigth, width];
            double[,] blue = new double[heigth, width];
            for (int i = 0; i < heigth; i++)
            {
                for (int j = 0; j < width; j++)
                {

                    red[i, j] = (image1[i, j].R) + ((1 - (image1[i, j].R / 255.0)) * (color.R));
                    green[i, j] = (image1[i, j].G) + ((1 - (image1[i, j].G / 255.0)) * (color.G));
                    blue[i, j] = (image1[i, j].B) + ((1 - (image1[i, j].B / 255.0)) * (color.B));
                    //red[i, j] = ((1 - (image1[i, j].R / 255.0)) * (color.R));
                    //green[i, j] = ((1 - (image1[i, j].G / 255.0)) * (color.G));
                    //blue[i, j] = ((1 - (image1[i, j].B / 255.0)) * (color.B));
                    // newImage[i, j].R = Convert.ToByte(image1[i, j].R & color.R);
                    // newImage[i, j].G = Convert.ToByte(image1[i, j].G & color.G);
                    //  newImage[i, j].B = Convert.ToByte(image1[i, j].B & color.B);

                    // red[i, j]= color.R - image1[i, j].R + newImage[i,j].R;
                    // green[i, j] = color.G - image1[i, j].G + newImage[i, j].G;
                    // blue[i, j] = color.B - image1[i, j].B + newImage[i, j].B;
                    // red[i, j] = Convert.ToByte(image1[i, j].R & color.R);
                    // green[i, j] = Convert.ToByte(image1[i, j].G & color.G);
                    // blue[i, j] = Convert.ToByte(image1[i, j].B & color.B);
                    // PixelOperation.ContrastCorrection(newImage,255);
                }
            }
            return FourierOperations.RecollectImage(red, green, blue, pp);
            // return PixelOperation.Normalization(newImage,heigth,width,red,green,blue);
            // return newImage;
            //return PixelOperation.GammaCorrection(newImage, 2);
        }

        /// <summary>
        /// Sums the iamges.
        /// </summary>
        /// <param name="image1">The image1.</param>
        /// <param name="color">The color.</param>
        /// <param name="fraction">The fraction.</param>
        /// <returns>
        /// new image sum imge1 and image2
        /// </returns>
        public static ImageStructure[,] SepiaEffect(ImageStructure[,] image)
        {
            int heigth = image.GetLength(0);
            int width = image.GetLength(1);
            double[,] red = new double[heigth, width];
            double[,] green = new double[heigth, width];
            double[,] blue = new double[heigth, width];
            for (int i = 0; i < heigth; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    red[i, j] = (int)(image[i, j].R * 0.393 + image[i, j].G * 0.769 + image[i, j].B * 0.189);

                    green[i, j] = (int)(image[i, j].R * 0.349 + image[i, j].G * 0.686 + image[i, j].B * 0.168);

                    blue[i, j] = (int)(image[i, j].R * 0.272 + image[i, j].G * 0.534 + image[i, j].B * 0.131);
                }
            }
            return FourierOperations.RecollectImage(red, green, blue, PostProcessing.Normalization);
        }

        public static Bitmap SepiaEffect(Bitmap imagebtm)
        {
            int heigth = imagebtm.Height;
            int width = imagebtm.Width;
            ImageStructure[,] image = Operations.ConvertBitmapToStructure(imagebtm);
            ImageStructure[,] newImage = new ImageStructure[heigth, width];
            double[,] red = new double[heigth, width];
            double[,] green = new double[heigth, width];
            double[,] blue = new double[heigth, width];
            for (int i = 0; i < heigth; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    red[i, j] = (int)(image[i, j].R * 0.393 + image[i, j].G * 0.769 + image[i, j].B * 0.189);

                    green[i, j] = (int)(image[i, j].R * 0.349 + image[i, j].G * 0.686 + image[i, j].B * 0.168);

                    blue[i, j] = (int)(image[i, j].R * 0.272 + image[i, j].G * 0.534 + image[i, j].B * 0.131);
                }
            }
            return Operations.DisplayMatrix(FourierOperations.RecollectImage(red, green, blue, PostProcessing.CuttOff));
        }

    }
}